import { _decorator, Component, Node, director, sys } from 'cc'
import levels, { ILevel } from '../../Levels'
import DataManager, { IRecord } from '../../Runtime/DataManager'
import { createUINode } from '../../Utils'
import { TILE_HEIGHT, TILE_WIDTH } from '../Tile/TileManager'
import { TileMapManager } from '../Tile/TileMapManager'
import EventManager from '../../Runtime/EventManager'
import { DIRECTION_ENUM, ENTITY_STATE_ENUM, ENTITY_TYPE_ENUM, EVENT_ENUM, SCENE_ENUM } from '../../Enum'
import { PlayerManager } from '../Player/PlayerManager'
import { WoodenSkeletonStateManager } from '../WoodenSkeleton/WoodenSkeletonManager'
import { DoorManager } from '../Door/DoorManager'
import { IronSkeletonManager } from '../IronSkeleton/IronSkeletonManager'
import { BurstManager } from '../Burst/BurstManager'
import { SpikesManager } from '../Spikes/SpikesManager'
import { SmokeManager } from '../Smoke/SmokeManager'
import { FaderManager } from '../../Runtime/FaderManager'
import { ShakeManager } from '../UI/ShakeManager'

const { ccclass, property } = _decorator

/**
 * Predefined variables
 * Name = BattleManager
 * DateTime = Tue Jul 05 2022 16:40:00 GMT+0800 (中国标准时间)
 * Author = Zero_Y
 * FileBasename = BattleManager.ts
 * FileBasenameNoExtension = BattleManager
 * URL = db://assets/Scripts/Scene/BattleManager.ts
 * ManualUrl = https://docs.cocos.com/creator/3.4/manual/zh/
 *
 */

const LOCAL_STORAGE_DATA_KEY = 'LOCAL_STORAGE_DATA_KEY'

@ccclass('BattleManager')
export class BattleManager extends Component {
  level: ILevel
  stage: Node
  smokeLayer: Node
  inited: boolean = false

  start() {
    this.generateStage()
    this.initLevel()
  }

  onLoad() {
    // 加载关卡
    DataManager.Instance.levelIndex = this.getStorage()
    // 绑定事件-关卡切换
    EventManager.Instance.on(EVENT_ENUM.NEXT_LEVEL, this.nextLevel, this)
    // 绑定事件-进入下一关卡
    EventManager.Instance.on(EVENT_ENUM.PLAYER_MOVE_END, this.checkArrived, this)
    // 绑定事件-显示烟雾
    EventManager.Instance.on(EVENT_ENUM.SHOW_SMOKE, this.generateSmoke, this)
    // 保存步骤
    EventManager.Instance.on(EVENT_ENUM.RECORD_STEP, this.record, this)
    // 撤回步骤
    EventManager.Instance.on(EVENT_ENUM.REVOKE_STEP, this.revoke, this)
    // 重新开始关卡
    EventManager.Instance.on(EVENT_ENUM.RESTART_LEVEL, this.initLevel, this)
    // 退出
    EventManager.Instance.on(EVENT_ENUM.QUIT_BATTLE, this.outQuit, this)
  }

  onDestroy() {
    // 解绑事件
    EventManager.Instance.off(EVENT_ENUM.NEXT_LEVEL, this.nextLevel)
    EventManager.Instance.off(EVENT_ENUM.PLAYER_MOVE_END, this.checkArrived)
    EventManager.Instance.off(EVENT_ENUM.SHOW_SMOKE, this.generateSmoke)
    EventManager.Instance.off(EVENT_ENUM.RECORD_STEP, this.record)
    EventManager.Instance.off(EVENT_ENUM.REVOKE_STEP, this.revoke)
    EventManager.Instance.off(EVENT_ENUM.RESTART_LEVEL, this.initLevel)
    EventManager.Instance.off(EVENT_ENUM.QUIT_BATTLE, this.outQuit)
    EventManager.Instance.clear()
  }

  // 创建stage
  generateStage() {
    this.stage = createUINode()
    this.stage.setParent(this.node)
    this.stage.addComponent(ShakeManager)
  }

  async initLevel() {
    // 加载关卡地图数据
    const level = levels[`level${DataManager.Instance.levelIndex}`]
    if (level) {
      if (this.inited) {
        await FaderManager.Instance.fadeIn(1)
      } else {
        await FaderManager.Instance.mask()
      }
      this.clearLevel()
      this.level = level
      // 将数据存入数据中心
      DataManager.Instance.mapInfo = this.level.mapInfo
      DataManager.Instance.mapRowCount = this.level.mapInfo.length || 0
      DataManager.Instance.mapColumnCount = this.level.mapInfo[0].length || 0
      await Promise.all([
        // 构建地图
        this.generateTileMap(),
        //构建地裂
        this.generateBurst(),
        // 构建地刺
        this.generateSpikes(),
        // 存放烟雾
        this.generateSmokeLayer(),
        // 构建门
        this.generateDoor(),
        // 构建NPC
        this.generateEnemies(),
        // 构建玩家
        this.generatePlayer(),
      ])
      await FaderManager.Instance.fadeOut(1)
      this.inited = true
    } else {
      this.outQuit()
    }
  }

  // 关卡切换-下一关
  nextLevel() {
    DataManager.Instance.levelIndex++
    this.initLevel()
    this.setStorage()
  }

  // 关卡清空
  clearLevel() {
    this.stage.destroyAllChildren()
    DataManager.Instance.reset()
  }

  //创建地图
  async generateTileMap() {
    // 生成瓦片地图节点
    const tileMap = new Node()
    // 设置父级
    tileMap.setParent(this.stage)
    // 给瓦片添加脚本
    const tileMapManager = tileMap.addComponent(TileMapManager)
    // 执行脚本初始化方法
    await tileMapManager.init()
    this.adaptPos()
  }
  // 对地图进行居中适配
  adaptPos() {
    // 向左上偏移自身宽度的一半
    const disX = (TILE_WIDTH * DataManager.Instance.mapRowCount) / 2
    const disY = (TILE_HEIGHT * DataManager.Instance.mapColumnCount) / 2
    this.stage.getComponent(ShakeManager).stop()
    this.stage.setPosition(-disX, disY)
  }
  // 创建人物
  async generatePlayer() {
    const player = createUINode()
    player.setParent(this.stage)
    const playerManager = player.addComponent(PlayerManager)
    await playerManager.init(this.level.player)
    DataManager.Instance.player = playerManager

    EventManager.Instance.emit(EVENT_ENUM.PLAYER_BORN, true)
  }
  // 创建NPC
  async generateEnemies() {
    const enemies = this.level.enemies
    const promise = []
    for (let i = 0; i < enemies.length; i++) {
      const node = createUINode()
      node.setParent(this.stage)
      // 判断NPC类型
      const Manager =
        enemies[i].type === ENTITY_TYPE_ENUM.SKELETON_WOODEN ? WoodenSkeletonStateManager : IronSkeletonManager
      const manager = node.addComponent(Manager)
      promise.push(manager.init(enemies[i]))
      DataManager.Instance.enemies.push(manager)
    }
    await Promise.all(promise)
  }
  // 创建门
  async generateDoor() {
    const door = createUINode()
    door.setParent(this.stage)
    const doorManager = door.addComponent(DoorManager)
    await doorManager.init(this.level.door)
    DataManager.Instance.door = doorManager
  }

  // 创建地裂
  async generateBurst() {
    const bursts = this.level.bursts
    const promise = []
    for (let i = 0; i < bursts.length; i++) {
      const burst = createUINode()
      burst.setParent(this.stage)
      const burstManager = burst.addComponent(BurstManager)
      promise.push(burstManager.init(bursts[i]))
      DataManager.Instance.bursts.push(burstManager)
    }
    await Promise.all(promise)
  }

  //创建地刺
  async generateSpikes() {
    const spikes = this.level.spikes
    const promise = []
    for (let i = 0; i < spikes.length; i++) {
      const spikesUI = createUINode()
      spikesUI.setParent(this.stage)
      const spikesManager = spikesUI.addComponent(SpikesManager)
      promise.push(spikesManager.init(spikes[i]))
      DataManager.Instance.spikes.push(spikesManager)
    }
    await Promise.all(promise)
  }

  // 进入下一关卡
  async checkArrived() {
    const { x: playX, y: playY } = DataManager.Instance.player
    const { x: doorX, y: doorY, state: doorState } = DataManager.Instance.door
    if (playX === doorX && playY === doorY && doorState === ENTITY_STATE_ENUM.DEATH) {
      EventManager.Instance.emit(EVENT_ENUM.NEXT_LEVEL)
    }
  }

  // 生成烟雾
  async generateSmoke(x: number, y: number, direction: DIRECTION_ENUM) {
    const item = DataManager.Instance.smokes.find(i => i.state === ENTITY_STATE_ENUM.DEATH)
    // 如果有死了的烟雾，把它激活，而不是直接生成
    if (item) {
      item.x = x
      item.y = y
      item.state = ENTITY_STATE_ENUM.IDLE
      item.direction = direction
      this.node.setPosition(x * TILE_WIDTH - TILE_WIDTH * 1.5, -y * TILE_HEIGHT + TILE_HEIGHT * 1.5)
      return
    }
    const smoke = createUINode()
    smoke.setParent(this.smokeLayer)
    const smokeManager = smoke.addComponent(SmokeManager)
    await smokeManager.init({
      x,
      y,
      direction,
      type: ENTITY_TYPE_ENUM.SMOKE,
      state: ENTITY_STATE_ENUM.IDLE,
    })
    DataManager.Instance.smokes.push(smokeManager)
  }

  // 生成烟雾，为了让player带动烟雾，将他设置位父级
  async generateSmokeLayer() {
    this.smokeLayer = createUINode()
    this.smokeLayer.setParent(this.stage)
  }

  setStorage() {
    sys.localStorage.setItem(LOCAL_STORAGE_DATA_KEY, String(DataManager.Instance.levelIndex)) //存储关卡数据
  }

  getStorage() {
    const levelIndex = sys.localStorage.getItem(LOCAL_STORAGE_DATA_KEY)
    return levelIndex ? Number(levelIndex) || 1 : 1
  }

  // 记录操作
  record() {
    const item: IRecord = {
      player: {
        x: DataManager.Instance.player.targetX,
        y: DataManager.Instance.player.targetY,
        state:
          DataManager.Instance.player.state === ENTITY_STATE_ENUM.IDLE ||
          DataManager.Instance.player.state === ENTITY_STATE_ENUM.DEATH ||
          DataManager.Instance.player.state === ENTITY_STATE_ENUM.AIRDEATH
            ? DataManager.Instance.player.state
            : ENTITY_STATE_ENUM.IDLE,
        direction: DataManager.Instance.player.direction,
        type: DataManager.Instance.player.type,
      },
      door: {
        x: DataManager.Instance.door.x,
        y: DataManager.Instance.door.y,
        state: DataManager.Instance.door.state,
        direction: DataManager.Instance.door.direction,
        type: DataManager.Instance.door.type,
      },
      enemies: DataManager.Instance.enemies.map(({ x, y, state, direction, type }) => {
        return {
          x,
          y,
          state,
          direction,
          type,
        }
      }),
      spikes: DataManager.Instance.spikes.map(({ x, y, count, type }) => {
        return {
          x,
          y,
          count,
          type,
        }
      }),
      bursts: DataManager.Instance.bursts.map(({ x, y, state, direction, type }) => {
        return {
          x,
          y,
          state,
          direction,
          type,
        }
      }),
    }

    DataManager.Instance.records.push(item)
  }

  // 撤回操作
  revoke() {
    const data = DataManager.Instance.records.pop()
    if (data) {
      DataManager.Instance.player.x = DataManager.Instance.player.targetX = data.player.x
      DataManager.Instance.player.y = DataManager.Instance.player.targetY = data.player.y
      DataManager.Instance.player.state = data.player.state
      DataManager.Instance.player.direction = data.player.direction

      for (let i = 0; i < data.enemies.length; i++) {
        const item = data.enemies[i]
        DataManager.Instance.enemies[i].x = item.x
        DataManager.Instance.enemies[i].y = item.y
        DataManager.Instance.enemies[i].state = item.state
        DataManager.Instance.enemies[i].direction = item.direction
      }

      for (let i = 0; i < data.spikes.length; i++) {
        const item = data.spikes[i]
        DataManager.Instance.spikes[i].x = item.x
        DataManager.Instance.spikes[i].y = item.y
        DataManager.Instance.spikes[i].count = item.count
      }

      for (let i = 0; i < data.bursts.length; i++) {
        const item = data.bursts[i]
        DataManager.Instance.bursts[i].x = item.x
        DataManager.Instance.bursts[i].y = item.y
        DataManager.Instance.bursts[i].state = item.state
      }

      DataManager.Instance.door.x = data.door.x
      DataManager.Instance.door.y = data.door.y
      DataManager.Instance.door.state = data.door.state
      DataManager.Instance.door.direction = data.door.direction
    }
  }

  // 退出关卡
  outQuit() {
    this.node.destroy()
    director.loadScene(SCENE_ENUM.Start)
  }
}
